﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace YArchitech.Controls.ImgListView
{
	public static class Utility
	{
		[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		[return: MarshalAs(UnmanagedType.Bool)]
		private static extern bool GetFileAttributesEx(string lpFileName, Utility.GET_FILEEX_INFO_LEVELS fInfoLevelId, out Utility.WIN32_FILE_ATTRIBUTE_DATA fileData);

		[DllImport("shell32.dll", CharSet = CharSet.Auto)]
		private static extern IntPtr SHGetFileInfo(string pszPath, FileAttributes dwFileAttributes, out Utility.SHFILEINFO psfi, uint cbFileInfo, Utility.SHGFI uFlags);

		public static string FormatSize(long size)
		{
			double num = 1024.0;
			double num2 = (double)size;
			string[] array = new string[]
			{
				"B",
				"KB",
				"MB",
				"GB",
				"TB",
				"PB"
			};
			int num3 = 0;
			while (num2 > num)
			{
				num2 /= num;
				num3++;
			}
			return string.Format("{0} {1}", Math.Round(num2, 2), array[num3]);
		}

		private static byte ReadExifByte(byte[] value)
		{
			return value[0];
		}

		private static string ReadExifAscii(byte[] value)
		{
			int num = Array.IndexOf<byte>(value, 0);
			if (num == -1)
			{
				num = value.Length;
			}
			return Encoding.ASCII.GetString(value, 0, num);
		}

		private static DateTime ReadExifDateTime(byte[] value)
		{
			return DateTime.ParseExact(Utility.ReadExifAscii(value), "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture);
		}

		private static ushort ReadExifUShort(byte[] value)
		{
			return BitConverter.ToUInt16(value, 0);
		}

		private static uint ReadExifUInt(byte[] value)
		{
			return BitConverter.ToUInt32(value, 0);
		}

		private static int ReadExifInt(byte[] value)
		{
			return BitConverter.ToInt32(value, 0);
		}

		private static string ReadExifURational(byte[] value)
		{
			return BitConverter.ToUInt32(value, 0).ToString() + "/" + BitConverter.ToUInt32(value, 4).ToString();
		}

		private static string ReadExifRational(byte[] value)
		{
			return BitConverter.ToInt32(value, 0).ToString() + "/" + BitConverter.ToInt32(value, 4).ToString();
		}

		private static float ReadExifFloat(byte[] value)
		{
			uint num = BitConverter.ToUInt32(value, 0);
			uint num2 = BitConverter.ToUInt32(value, 4);
			if (num2 == 0u)
			{
				return 0f;
			}
			return num / num2;
		}

		internal static int DrawStringPair(Graphics g, System.Drawing.Rectangle r, string caption, string text, Font font, Brush captionBrush, Brush textBrush)
		{
			int result;
			using (StringFormat stringFormat = new StringFormat())
			{
				stringFormat.Alignment = StringAlignment.Near;
				stringFormat.LineAlignment = StringAlignment.Near;
				stringFormat.Trimming = StringTrimming.EllipsisCharacter;
				stringFormat.FormatFlags = StringFormatFlags.NoWrap;
				SizeF value = g.MeasureString(caption, font, r.Size, stringFormat);
				int num = (int)value.Height;
				if (value.Width > (float)r.Width)
				{
					value.Width = (float)r.Width;
				}
				System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(r.Location, Size.Ceiling(value));
				g.DrawString(caption, font, captionBrush, rectangle, stringFormat);
				rectangle.X += rectangle.Width;
				rectangle.Width = r.Width;
				if (rectangle.X < r.Right)
				{
					num = Math.Max(num, (int)g.MeasureString(text, font, r.Size, stringFormat).Height);
					rectangle = System.Drawing.Rectangle.Intersect(r, rectangle);
					g.DrawString(text, font, textBrush, rectangle, stringFormat);
				}
				result = num;
			}
			return result;
		}

		internal static Image ThumbnailFromImage(Image image, Size size, System.Drawing.Color backColor)
		{
			if (size.Width <= 0 || size.Height <= 0)
			{
				throw new ArgumentException();
			}
			Image image2 = null;
			try
			{
				Size sizedImageBounds = Utility.GetSizedImageBounds(image, size);
				image2 = new Bitmap(sizedImageBounds.Width, sizedImageBounds.Height);
				using (Graphics graphics = Graphics.FromImage(image2))
				{
					graphics.PixelOffsetMode = PixelOffsetMode.None;
					graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
					using (new SolidBrush(backColor))
					{
						graphics.FillRectangle(Brushes.White, 0, 0, sizedImageBounds.Width, sizedImageBounds.Height);
					}
					graphics.DrawImage(image, 0, 0, sizedImageBounds.Width, sizedImageBounds.Height);
				}
			}
			catch
			{
				if (image2 != null)
				{
					image2.Dispose();
				}
				image2 = null;
			}
			return image2;
		}

		internal static Image ThumbnailFromFile(string filename, Size size, UseEmbeddedThumbnails useEmbeddedThumbnails, System.Drawing.Color backColor)
		{
			if (size.Width <= 0 || size.Height <= 0)
			{
				throw new ArgumentException();
			}
			Image image = null;
			Image image2 = null;
			if (useEmbeddedThumbnails != UseEmbeddedThumbnails.Never)
			{
				try
				{
					using (FileStream fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
					{
						using (Image image3 = Image.FromStream(fileStream, false, false))
						{
							int[] propertyIdList = image3.PropertyIdList;
							int i = 0;
							while (i < propertyIdList.Length)
							{
								if (propertyIdList[i] == 20507)
								{
									using (MemoryStream memoryStream = new MemoryStream(image3.GetPropertyItem(20507).Value))
									{
										image = Image.FromStream(memoryStream);
									}
									if (useEmbeddedThumbnails == UseEmbeddedThumbnails.Auto && Math.Max((float)image.Width / (float)size.Width, (float)image.Height / (float)size.Height) < 1f)
									{
										image.Dispose();
										image = null;
										break;
									}
									break;
								}
								else
								{
									i++;
								}
							}
						}
					}
				}
				catch
				{
					if (image != null)
					{
						image.Dispose();
					}
					image = null;
				}
			}
			MemoryStream memoryStream2 = null;
			try
			{
				if (image == null)
				{
					using (FileStream fileStream2 = new FileStream(filename, FileMode.Open, FileAccess.Read))
					{
						byte[] array = new byte[6];
						fileStream2.Read(array, 0, 6);
						if (Encoding.ASCII.GetString(array) == "GIF89a")
						{
							fileStream2.Seek(0L, SeekOrigin.Begin);
							memoryStream2 = new MemoryStream();
							byte[] array2 = new byte[32768];
							int count;
							while ((count = fileStream2.Read(array2, 0, array2.Length)) > 0)
							{
								memoryStream2.Write(array2, 0, count);
							}
							memoryStream2.Seek(-1L, SeekOrigin.End);
							if (memoryStream2.ReadByte() != 59)
							{
								memoryStream2.WriteByte(59);
							}
							image = Image.FromStream(memoryStream2);
						}
					}
				}
			}
			catch
			{
				if (image != null)
				{
					image.Dispose();
				}
				image = null;
				if (memoryStream2 != null)
				{
					memoryStream2.Dispose();
				}
				memoryStream2 = null;
			}
			if (image == null)
			{
				try
				{
					image = Image.FromFile(filename);
				}
				catch
				{
					if (image != null)
					{
						image.Dispose();
					}
					image = null;
				}
			}
			if (image == null)
			{
				return null;
			}
			try
			{
				Size sizedImageBounds = Utility.GetSizedImageBounds(image, size);
				image2 = new Bitmap(image, sizedImageBounds.Width, sizedImageBounds.Height);
				using (Graphics graphics = Graphics.FromImage(image2))
				{
					graphics.PixelOffsetMode = PixelOffsetMode.None;
					graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
					graphics.Clear(backColor);
					graphics.DrawImage(image, 0, 0, sizedImageBounds.Width, sizedImageBounds.Height);
				}
			}
			catch
			{
				if (image2 != null)
				{
					image2.Dispose();
				}
				image2 = null;
			}
			finally
			{
				if (image != null)
				{
					image.Dispose();
				}
				image = null;
				if (memoryStream2 != null)
				{
					memoryStream2.Dispose();
				}
				memoryStream2 = null;
			}
			return image2;
		}

		internal static Size GetSizedImageBounds(Image image, Size fit)
		{
			float num = Math.Max((float)image.Width / (float)fit.Width, (float)image.Height / (float)fit.Height);
			if (num < 1f)
			{
				num = 1f;
			}
			int width = (int)Math.Round((double)((float)image.Width / num));
			int height = (int)Math.Round((double)((float)image.Height / num));
			return new Size(width, height);
		}

		internal static System.Drawing.Rectangle GetSizedImageBounds(Image image, System.Drawing.Rectangle fit, float hAlign, float vAlign)
		{
			Size sizedImageBounds = Utility.GetSizedImageBounds(image, fit.Size);
			int x = fit.Left + (int)(hAlign / 100f * (float)(fit.Width - sizedImageBounds.Width));
			int y = fit.Top + (int)(vAlign / 100f * (float)(fit.Height - sizedImageBounds.Height));
			return new System.Drawing.Rectangle(x, y, sizedImageBounds.Width, sizedImageBounds.Height);
		}

		internal static System.Drawing.Rectangle GetSizedImageBounds(Image image, System.Drawing.Rectangle fit)
		{
			return Utility.GetSizedImageBounds(image, fit, 50f, 50f);
		}

		private static GraphicsPath GetRoundedRectanglePath(int x, int y, int width, int height, int radius)
		{
			GraphicsPath graphicsPath = new GraphicsPath();
			graphicsPath.AddLine(x + radius, y, x + width - radius, y);
			if (radius > 0)
			{
				graphicsPath.AddArc(x + width - 2 * radius, y, 2 * radius, 2 * radius, 270f, 90f);
			}
			graphicsPath.AddLine(x + width, y + radius, x + width, y + height - radius);
			if (radius > 0)
			{
				graphicsPath.AddArc(x + width - 2 * radius, y + height - 2 * radius, 2 * radius, 2 * radius, 0f, 90f);
			}
			graphicsPath.AddLine(x + width - radius, y + height, x + radius, y + height);
			if (radius > 0)
			{
				graphicsPath.AddArc(x, y + height - 2 * radius, 2 * radius, 2 * radius, 90f, 90f);
			}
			graphicsPath.AddLine(x, y + height - radius, x, y + radius);
			if (radius > 0)
			{
				graphicsPath.AddArc(x, y, 2 * radius, 2 * radius, 180f, 90f);
			}
			return graphicsPath;
		}

		public static void FillRoundedRectangle(Graphics graphics, Brush brush, int x, int y, int width, int height, int radius)
		{
			using (GraphicsPath roundedRectanglePath = Utility.GetRoundedRectanglePath(x, y, width, height, radius))
			{
				graphics.FillPath(brush, roundedRectanglePath);
			}
		}

		public static void FillRoundedRectangle(Graphics graphics, Brush brush, float x, float y, float width, float height, float radius)
		{
			Utility.FillRoundedRectangle(graphics, brush, (int)x, (int)y, (int)width, (int)height, (int)radius);
		}

		public static void FillRoundedRectangle(Graphics graphics, Brush brush, System.Drawing.Rectangle rect, int radius)
		{
			Utility.FillRoundedRectangle(graphics, brush, rect.Left, rect.Top, rect.Width, rect.Height, radius);
		}

		public static void FillRoundedRectangle(Graphics graphics, Brush brush, RectangleF rect, float radius)
		{
			Utility.FillRoundedRectangle(graphics, brush, (int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height, (int)radius);
		}

		public static void DrawRoundedRectangle(Graphics graphics, Pen pen, int x, int y, int width, int height, int radius)
		{
			using (GraphicsPath roundedRectanglePath = Utility.GetRoundedRectanglePath(x, y, width, height, radius))
			{
				graphics.DrawPath(pen, roundedRectanglePath);
			}
		}

		public static void DrawRoundedRectangle(Graphics graphics, Pen pen, float x, float y, float width, float height, float radius)
		{
			Utility.DrawRoundedRectangle(graphics, pen, (int)x, (int)y, (int)width, (int)height, (int)radius);
		}

		public static void DrawRoundedRectangle(Graphics graphics, Pen pen, System.Drawing.Rectangle rect, int radius)
		{
			Utility.DrawRoundedRectangle(graphics, pen, rect.Left, rect.Top, rect.Width, rect.Height, radius);
		}

		public static void DrawRoundedRectangle(Graphics graphics, Pen pen, RectangleF rect, float radius)
		{
			Utility.DrawRoundedRectangle(graphics, pen, (int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height, (int)radius);
		}

		private const int MAX_PATH = 260;

		private const int MAX_TYPE = 80;

		private const int PropertyTagThumbnailData = 20507;

		private const int PropertyTagThumbnailImageWidth = 20512;

		private const int PropertyTagThumbnailImageHeight = 20513;

		private const int PropertyTagImageDescription = 270;

		private const int PropertyTagEquipmentModel = 272;

		private const int PropertyTagDateTime = 306;

		private const int PropertyTagArtist = 315;

		private const int PropertyTagCopyright = 33432;

		private const int PropertyTagExposureTime = 33434;

		private const int PropertyTagFNumber = 33437;

		private const int PropertyTagISOSpeed = 34855;

		private const int PropertyTagShutterSpeed = 37377;

		private const int PropertyTagAperture = 37378;

		private const int PropertyTagUserComment = 37510;

		private enum GET_FILEEX_INFO_LEVELS
		{
			GetFileExInfoStandard,
			GetFileExMaxInfoLevel
		}

		private struct WIN32_FILE_ATTRIBUTE_DATA
		{
			public FileAttributes dwFileAttributes;

			public Utility.FILETIME ftCreationTime;

			public Utility.FILETIME ftLastAccessTime;

			public Utility.FILETIME ftLastWriteTime;

			public uint nFileSizeHigh;

			public uint nFileSizeLow;
		}

		private struct FILETIME
		{
			public DateTime Value
			{
				get
				{
					return DateTime.FromFileTimeUtc((long)((ulong)this.dwHighDateTime << 32 | (ulong)this.dwLowDateTime));
				}
			}

			public uint dwLowDateTime;

			public uint dwHighDateTime;
		}

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		private struct SHFILEINFO
		{
			public IntPtr hIcon;

			public int iIcon;

			public uint dwAttributes;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
			public string szDisplayName;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
			public string szTypeName;
		}

		[Flags]
		private enum SHGFI : uint
		{
			Icon = 256u,
			DisplayName = 512u,
			TypeName = 1024u,
			Attributes = 2048u,
			IconLocation = 4096u,
			ExeType = 8192u,
			SysIconIndex = 16384u,
			LinkOverlay = 32768u,
			Selected = 65536u,
			Attr_Specified = 131072u,
			LargeIcon = 0u,
			SmallIcon = 1u,
			OpenIcon = 2u,
			ShellIconSize = 4u,
			PIDL = 8u,
			UseFileAttributes = 16u,
			AddOverlays = 32u,
			OverlayIndex = 64u
		}

		internal class ShellImageFileInfo
		{
			public bool Error { get; private set; }

			public FileAttributes FileAttributes { get; private set; }

			public DateTime CreationTime { get; private set; }

			public DateTime LastAccessTime { get; private set; }

			public DateTime LastWriteTime { get; private set; }

			public string Extension { get; private set; }

			public string DirectoryName { get; private set; }

			public string DisplayName { get; private set; }

			public long Size { get; private set; }

			public string TypeName { get; private set; }

			public Size Dimensions { get; private set; }

			public SizeF Resolution { get; private set; }

			public string ImageDescription { get; private set; }

			public string EquipmentModel { get; private set; }

			public DateTime DateTaken { get; private set; }

			public string Artist { get; private set; }

			public string Copyright { get; private set; }

			public string ExposureTime { get; private set; }

			public float FNumber { get; private set; }

			public ushort ISOSpeed { get; private set; }

			public string ShutterSpeed { get; private set; }

			public string ApertureValue { get; private set; }

			public string UserComment { get; private set; }

			public ShellImageFileInfo(string path)
			{
				if (Utility.ShellImageFileInfo.cachedFileTypes == null)
				{
					Utility.ShellImageFileInfo.cachedFileTypes = new Dictionary<string, string>();
				}
				try
				{
					FileInfo fileInfo = new FileInfo(path);
					this.FileAttributes = fileInfo.Attributes;
					this.CreationTime = fileInfo.CreationTime;
					this.LastAccessTime = fileInfo.LastAccessTime;
					this.LastWriteTime = fileInfo.LastWriteTime;
					this.Size = fileInfo.Length;
					this.DirectoryName = fileInfo.DirectoryName;
					this.DisplayName = fileInfo.Name;
					this.Extension = fileInfo.Extension;
					string szTypeName;
					if (!Utility.ShellImageFileInfo.cachedFileTypes.TryGetValue(this.Extension, out szTypeName))
					{
						Utility.SHFILEINFO shfileinfo = default(Utility.SHFILEINFO);
						if (this.structSize == 0u)
						{
							this.structSize = (uint)Marshal.SizeOf(shfileinfo);
						}
						Utility.SHGetFileInfo(path, (FileAttributes)0, out shfileinfo, this.structSize, Utility.SHGFI.TypeName);
						szTypeName = shfileinfo.szTypeName;
						Utility.ShellImageFileInfo.cachedFileTypes.Add(this.Extension, szTypeName);
					}
					this.TypeName = szTypeName;
					using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
					{
						using (Image image = Image.FromStream(fileStream, false, false))
						{
							this.Dimensions = image.Size;
							this.Resolution = new SizeF(image.HorizontalResolution, image.VerticalResolution);
							foreach (PropertyItem propertyItem in image.PropertyItems)
							{
								int id = propertyItem.Id;
								if (id <= 33432)
								{
									if (id <= 272)
									{
										if (id != 270)
										{
											if (id == 272)
											{
												this.EquipmentModel = Utility.ReadExifAscii(propertyItem.Value);
											}
										}
										else
										{
											this.ImageDescription = Utility.ReadExifAscii(propertyItem.Value);
										}
									}
									else if (id != 306)
									{
										if (id != 315)
										{
											if (id == 33432)
											{
												this.Copyright = Utility.ReadExifAscii(propertyItem.Value);
											}
										}
										else
										{
											this.Artist = Utility.ReadExifAscii(propertyItem.Value);
										}
									}
									else
									{
										this.DateTaken = Utility.ReadExifDateTime(propertyItem.Value);
									}
								}
								else if (id <= 34855)
								{
									if (id != 33434)
									{
										if (id != 33437)
										{
											if (id == 34855)
											{
												this.ISOSpeed = Utility.ReadExifUShort(propertyItem.Value);
											}
										}
										else
										{
											this.FNumber = Utility.ReadExifFloat(propertyItem.Value);
										}
									}
									else
									{
										this.ExposureTime = Utility.ReadExifURational(propertyItem.Value);
									}
								}
								else if (id != 37377)
								{
									if (id != 37378)
									{
										if (id == 37510)
										{
											this.UserComment = Utility.ReadExifAscii(propertyItem.Value);
										}
									}
									else
									{
										this.ApertureValue = Utility.ReadExifURational(propertyItem.Value);
									}
								}
								else
								{
									this.ShutterSpeed = Utility.ReadExifRational(propertyItem.Value);
								}
							}
						}
					}
					this.Error = false;
				}
				catch
				{
					this.Error = true;
				}
			}

			private static Dictionary<string, string> cachedFileTypes;

			private uint structSize;
		}
	}
}
